/**
 * 集合
 */
 interface setItemType<T> {
    [propsName: string]: T
}

export default class Set<T> {
    private items: setItemType<T>
    constructor() {
        this.items = {}
    }
    //ADT

    /**
     * 判断集合里是否有某个元素
     * @param element 
     * @returns 
     */
    has(element: any): boolean {
        return Object.prototype.hasOwnProperty.call(this.items, element)
    }

    /**
     * 向集合添加一个元素
     * @param element 
     * @returns 
     */
    add(element: any) {
        if (!this.has(element)) {
            this.items[element] = element
            return true
        }
        return false
    }

    /**
     * 删除集合里的某个元素
     * @param element 
     * @returns 
     */
    delete(element: any) {
        if (this.has(element)) {
            delete this.items[element]
            return true
        }
        return false
    }

    /**
     * 清空集合（移除集合里的所有元素）
     */
    clear() {
        this.items = {}
    }

    /**
     * 返回集合所包含元素的数量
     * @returns 
     */
    size() {
        let count = 0
        for (let key in this.items) {
            if (this.items.hasOwnProperty(key)) {
                count++
            }
        }
        return count
    }

    /**
     * 返回一个包含集合所有元素的数组
     * @returns 
     */
    values() {
        let values = []
        for (let key in this.items) {
            if (this.items.hasOwnProperty(key)) {
                values.push(key)
            }
        }
        return values
    }

    /**
     * 合并
     * @param otherSet 
     * @returns 
     */
    union(otherSet: Set<T>) {
        const unionSet = new Set()
        // const values = this.values()
        this.values().forEach(value => unionSet.add(value))
        otherSet.values().forEach(value => unionSet.add(value))
        return unionSet
    }

    /**
     * 交集
     * @param otherSet 
     * @returns 
     */
    intersection(otherSet: Set<T>) {
        const intersectionSet = new Set()
        const values = this.values()
        const otherValues = otherSet.values()
        let biggerSet = values
        let smallerSet = otherValues
        if (otherValues.length - values.length > 0) {
            biggerSet = otherValues
            smallerSet = values
        }
        smallerSet.forEach(value => {
            if (biggerSet.includes(value)) {
                intersectionSet.add(value)
            }
        })
        return intersectionSet
    }

    /**
     * 差集
     * @param otherSet 
     * @returns 
     */
    difference(otherSet: Set<T>) {
        const differenceSet = new Set()
        this.values().forEach(item => {
            if (!otherSet.has(item)) {
                differenceSet.add(item)
            }
        })
        return differenceSet
    }

    /**
     * 是否是子集
     * @param otherSet 
     * @returns 
     */
    isSubsetOf(otherSet: Set<T>) {
        if (this.size() > otherSet.size()) {
            return false
        }
        return this.values().every(item => {
            return otherSet.has(item)
        })
    } 
}
